﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace ZMHWcfServiceLibrary.ZMHPublisher
{
    // 注意: 使用“重构”菜单上的“重命名”命令，可以同时更改代码和配置文件中的接口名“IMyPublisService”。
    [ServiceContract]
    public interface IMyPublisService
    {
        [OperationContract]
        void DoWork();
    }
    public abstract class PublishService<T> where T : class
    {
        protected static void FireEvent(params object[] args)
        {
            StackFrame stackFrame = new StackFrame(1);
            string methodName = stackFrame.GetMethod().Name;
            if (methodName.Contains("."))
            {
                string[] parts = methodName.Split('.');
                methodName = parts[parts.Length - 1];
            }
            FireEvent(methodName, args);
        }
        static void FireEvent(string methodName, params object[] args)
        {
            PublishPersistent(methodName, args);
            PublishTransient(methodName, args);
        }

        private static void PublishTransient(string methodName, object[] args)
        {
            T[] subscribers = SubscriptionManager<T>.GetTransientList(methodName);
            Publish(subscribers, false, methodName, args);
        }

        private static void PublishPersistent(string methodName, object[] args)
        {
            T[] subscribers = SubscriptionManager<T>.GetPersistentList(methodName);
            Publish(subscribers, true, methodName, args);
        }

        private static void Publish(T[] subscribers, bool closeSubscribers, string methodName, object[] args)
        {
            //WaitCallback fire = delegate (object subscriber)
            //{
            //    Invoke(subscriber as T, methodName, args);
            //    if (closeSubscribers)
            //        using (subscriber as IDisposable) { }
            //};
            //Action<T> queueUp = delegate (T subscriber) {ThreadPool.QueueUserWorkItem(fire,subscriber); };
            //Array.ForEach(subscribers, queueUp);

            //void fire(object subscriber)
            //{
            //    Invoke(subscriber as T, methodName, args);
            //    if (closeSubscribers)
            //        using (subscriber as IDisposable) { }
            //}
            //void queueUp(T subscriber) { ThreadPool.QueueUserWorkItem(fire, subscriber); }
            //Array.ForEach(subscribers, queueUp);

            Array.ForEach(subscribers, (subscriber) =>
            {
                ThreadPool.QueueUserWorkItem((_subscriber) =>
                {
                    Invoke(subscriber as T, methodName, args);
                    if (closeSubscribers)
                        using (subscriber as IDisposable) { }
                }, subscriber);
            });
        }

        private static void Invoke(T subscriber, string methodName, object[] args)
        {
            Debug.Assert(subscriber != null);
            Type type = typeof(T);
            MethodInfo methodInfo = type.GetMethod(methodName);
            try
            {
                methodInfo.Invoke(subscriber, args);
            }
            catch (Exception ex) { Trace.WriteLine(ex.Message); }
        }
    }
}
